﻿//Copyright (c) Microsoft Corporation. All rights reserved.

using Microsoft.Ted.Wacel.TestConsole.Properties;
using Microsoft.Ted.Wacel;
using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Microsoft.Ted.Wacel.TestConsole
{
    public class TableStorageCubeTester
    {
        /// <summary>
        /// This test case adds a single data point to a simple cube (that has only a Time dimension and the default
        /// Data dimension) and then verifies if data is rolled up correctly.
        /// </summary>
        public static void SimplestCase()
        {
            TableStorage.Cube cube = TableStorage.Cube.GetSimpleCube(Settings.Default.StorageConnectionString);
            cube.Clear();
            cube.Update(new { Time = "Aug18", Value = 100.0 });
            VisualTester.AreEqual(100.0, (double)cube.Query(new { Time = "Aug" }).Value);
        }

        /// <summary>
        /// This test case tests the Free Dimension, which doesn't check member existence and allow coordniate with
        /// any value.
        /// </summary>
        public static void FreeDimension()
        {
            TableStorage.Cube cube = TableStorage.Cube.GetSimpleCube(Settings.Default.StorageConnectionString);
            cube.AddDimension(Dimension.CreateFreeDimension("Free"));
            cube.Clear();
            cube.Update(new { Time = "Nov11", Free = "FreeMember1", Value = 123.0 });
            cube.Update(new { Time = "Nov11", Free = "FreeMember2", Value = 456.0 });
            cube.Update(new { Time = "Nov10", Free = "FreeMember1", Value = 321.0 });
            VisualTester.AreEqual(444.0, (double)cube.Query(new { Time = "Nov", Free = "FreeMember1"}).Value);
            VisualTester.AreEqual(456.0, (double)cube.Query(new { Time = "Nov", Free = "FreeMember2"}).Value);
        }

        /// <summary>
        /// This test case tests statistics supported by the Cube: min, max, sum, average and median. The test
        /// populates November with random numbers and then verifies if all staticstics are all correctly calculated.
        /// </summary>
        public static void Statistics()
        {
            TableStorage.Cube cube = TableStorage.Cube.GetSimpleCube(Settings.Default.StorageConnectionString);
            cube.Clear();
            Random rand = new Random();
            double[] values = new double[30];
            double sum = 0;
            List<dynamic> dataPoints = new List<dynamic>();
            for (int i = 1; i <= 30; i++)
            {
                values[i - 1] = rand.NextDouble();
                sum += values[i - 1];
                dataPoints.Add(new { Time = "Nov" + i.ToString(), Value = values[i - 1] });
            }
            cube.Update(dataPoints);
            Array.Sort(values);
            VisualTester.AreEqual(sum, (double)cube.Query(new { Time = "Nov" }).Value);         //sum
            VisualTester.AreEqual(sum/30, (double)cube.Query(new { Time = "Nov" }).Average);    //average
            VisualTester.AreEqual(values[0], (double)cube.Query(new { Time = "Nov" }).Min);     //min
            VisualTester.AreEqual(values[29], (double)cube.Query(new { Time = "Nov" }).Max);    //max
        }

        /// <summary>
        /// This test case tests rollup by the Time dimension
        /// </summary>
        public static void SingleRollup()
        {
            TableStorage.Cube cube = TableStorage.Cube.GetSimpleCube(Settings.Default.StorageConnectionString);
            cube.Clear();
            VisualTester.AreEqual(0.0, (double)cube.Query(new { Time = "Nov" }).Value);

            Stopwatch watch = new Stopwatch();
            watch.Start();

            cube.Update(new { Time = "Jan1", Value = 100.0 },
                        new { Time = "Jan23", Value = 200.0 },
                        new { Time = "Feb28", Value = 155.0 },
                        new { Time = "Aug18", Value = 50.0});

            watch.Stop();
            Console.WriteLine("Time to update 3 data points:" + watch.ElapsedMilliseconds + "(ms)");

            watch.Restart();
            
            VisualTester.AreEqual(300.0, (double)cube.Query(new { Time = "Jan" }).Value);
            VisualTester.AreEqual(155.0, (double)cube.Query(new { Time = "Feb" }).Value);
            VisualTester.AreEqual(505.0, (double)cube.Query(new { Time = DateTime.Now.Year.ToString() }).Value);
            
            watch.Stop();
            Console.WriteLine("Time to make 3 queires:" + watch.ElapsedMilliseconds + "(ms)");
        }

        public static void MultiRollup()
        {
            TableStorage.Cube cube = TableStorage.Cube.GetSimpleCube(Settings.Default.StorageConnectionString);
            cube.AddDimension(Dimension.CreateFlatDimension("StatusCode", "200", "404", "500"));

            Stopwatch watch = new Stopwatch();
            watch.Start();

            cube.Update(
                new {Time = "Jan1", StatusCode="200", Value = 100.0},
                new {Time = "Jan23", StatusCode="404", Value = 200.0},
                new {Time = "Jan23", StatusCode="200", Value = 123.0},
                new { Time = "Feb14", StatusCode = "500", Value = 155.0 },
                new { Time = "Feb28", StatusCode = "500", Value = 155.0 },
                new {Time = DateTime.Now, StatusCode = "500", Value = 35.0});

            watch.Stop();
            Console.WriteLine("Time to update 4 data points:" + watch.ElapsedMilliseconds + "(ms).");

            watch.Restart();
            
            VisualTester.AreEqual(223.0, (double)cube.Query(new { Time = "Jan", StatusCode = "200" }).Value);
            VisualTester.AreEqual(200.0, (double)cube.Query(new { Time = "Jan", StatusCode = "404" }).Value);
            VisualTester.AreEqual(310.0, (double)cube.Query(new { Time = "Feb", StatusCode = "500" }).Value);
            VisualTester.AreEqual(35.0, (double)cube.Query(new { Time = DateTime.Now.ToString("MMM") , StatusCode = "500" }).Value);
            VisualTester.AreEqual(DateTime.Now.ToString("MMM") == "Jan" ? 200.0 : 0.0, (double)cube.Query(new { Time = DateTime.Now.ToString("MMM"), StatusCode = "404" }).Value);
            
            watch.Stop();
            Console.WriteLine("Time to make 5 queires:" + watch.ElapsedMilliseconds + "(ms).");
        }
        public static void DrilldownTwoDirections()
        {
            TableStorage.Cube cube = TableStorage.Cube.GetSimpleCube(Settings.Default.StorageConnectionString);
            cube.Dimensions.Add("StatusCode", Dimension.CreateFlatDimension("StatusCode", "200", "404", "500"));

            Stopwatch watch = new Stopwatch();
            watch.Start();

            cube.Update(new {Time = "Jan1", StatusCode="200", Value = 100.0},
                        new {Time = "Jan23", StatusCode="404", Value = 200.0},
                        new {Time = "Jan23", StatusCode="200", Value = 123.0},
                        new {Time = "Feb28", StatusCode = "500", Value = 155.0});

            watch.Stop();
            Console.WriteLine("Time to update 4 data points:" + watch.ElapsedMilliseconds + "(ms).");
            watch.Restart();

            var datapoint = cube.Query(new { Time = "Jan", StatusCode = "200" });
            
            watch.Stop();
            Console.WriteLine("Time to make 1 query:" + watch.ElapsedMilliseconds + "(ms)");
            watch.Restart();
            
            var children = cube.Drilldown(datapoint, "Time");
            VisualTester.AreEqual(31, children.Count);
            children = cube.Drilldown(datapoint, "StatusCode");
            VisualTester.AreEqual(0, children.Count);
            
            watch.Stop();
            Console.WriteLine("Time to make 2 drilldowns:" + watch.ElapsedMilliseconds + "(ms)");
        }
        public static void MinuteCube()
        {
            TableStorage.Cube cube = new TableStorage.Cube("mycube", Settings.Default.StorageConnectionString);
            
            cube.Dimensions.Add("Time", Dimension.GetTimeDimensionMonthDayHour5Minutes(2013));
            cube.Update(new { Time = "Oct2_13_35", Value = 100.0 }, new { Time = "Oct2_12_5", Value = 200.0 });

            Stopwatch watch = new Stopwatch();
            watch.Start();
            
            var datapoint = cube.Query(new { Time = "Oct2_12" });
            VisualTester.AreEqual(200.0, (double)datapoint.Value);
            datapoint = cube.Query(new { Time = "Oct2" });
            VisualTester.AreEqual(300.0, (double)datapoint.Value);
            datapoint = cube.Query(new { Time = "Oct" });
            VisualTester.AreEqual(300.0, (double)datapoint.Value);
            datapoint = cube.Query(new { Time = "2013" });
            VisualTester.AreEqual(300.0, (double)datapoint.Value);
            
            watch.Stop();
            Console.WriteLine("Time to make 4 queires:" + watch.ElapsedMilliseconds + "(ms)");
        }    
    }
}
